{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [],
   "source": [
    "import math, random\n",
    "\n",
    "import gym\n",
    "import numpy as np\n",
    "\n",
    "import torch\n",
    "import torch.nn as nn\n",
    "import torch.optim as optim\n",
    "import torch.autograd as autograd \n",
    "import torch.nn.functional as F\n",
    "\n",
    "from common.layers import NoisyLinear\n",
    "from common.replay_buffer import ReplayBuffer"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 57,
   "metadata": {},
   "outputs": [],
   "source": [
    "from IPython.display import clear_output\n",
    "import matplotlib.pyplot as plt\n",
    "%matplotlib inline"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<h3>Use Cuda</h3>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 102,
   "metadata": {},
   "outputs": [],
   "source": [
    "USE_CUDA = torch.cuda.is_available()\n",
    "Variable = lambda *args, **kwargs: autograd.Variable(*args, **kwargs).cuda() if USE_CUDA else autograd.Variable(*args, **kwargs)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<h2>Cart Pole Environment</h2>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 103,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[33mWARN: gym.spaces.Box autodetected dtype as <type 'numpy.float32'>. Please provide explicit dtype.\u001b[0m\n"
     ]
    }
   ],
   "source": [
    "env_id = \"CartPole-v0\"\n",
    "env = gym.make(env_id)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<h2>Distributional Reinforcement Learning with Quantile Regression</h2>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 104,
   "metadata": {},
   "outputs": [],
   "source": [
    "class QRDQN(nn.Module):\n",
    "    def __init__(self, num_inputs, num_actions, num_quants):\n",
    "        super(QRDQN, self).__init__()\n",
    "        \n",
    "        self.num_inputs  = num_inputs\n",
    "        self.num_actions = num_actions\n",
    "        self.num_quants  = num_quants\n",
    "        \n",
    "        self.features = nn.Sequential(\n",
    "            nn.Linear(num_inputs, 32),\n",
    "            nn.ReLU(),\n",
    "            nn.Linear(32, 64),\n",
    "            nn.ReLU(),\n",
    "            nn.Linear(64, 128),\n",
    "            nn.ReLU(),\n",
    "            nn.Linear(128, self.num_actions * self.num_quants)\n",
    "        )\n",
    "        \n",
    "        #self.noisy_value1 = NoisyLinear(64, 128, use_cuda=USE_CUDA)\n",
    "        #self.noisy_value2 = NoisyLinear(128, self.num_actions * self.num_quants, use_cuda=USE_CUDA)\n",
    "        \n",
    "    def forward(self, x):\n",
    "        batch_size = x.size(0)\n",
    "\n",
    "        x = self.features(x)\n",
    "        \n",
    "        #x = self.noisy_value1(x)\n",
    "        #x = F.relu(x)\n",
    "        #x = self.noisy_value2(x)\n",
    "        x = x.view(batch_size, self.num_actions, self.num_quants)\n",
    "        \n",
    "        return x\n",
    "    \n",
    "    def q_values(self, x):\n",
    "        x = self.forward(x)\n",
    "        return x.mean(2)\n",
    "    \n",
    "    def reset_noise(self):\n",
    "        self.noisy_value1.reset_noise()\n",
    "        self.noisy_value2.reset_noise() \n",
    "        \n",
    "    def act(self, state, epsilon):\n",
    "        if random.random() > epsilon:\n",
    "            state = Variable(torch.FloatTensor(np.array(state, dtype=np.float32)).unsqueeze(0), volatile=True)\n",
    "            qvalues = self.forward(state).mean(2)\n",
    "            action  = qvalues.max(1)[1]\n",
    "            action  = action.data.cpu().numpy()[0]\n",
    "        else:\n",
    "            action = random.randrange(self.num_actions)\n",
    "        return action"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 105,
   "metadata": {},
   "outputs": [],
   "source": [
    "def projection_distribution(dist, next_state, reward, done):\n",
    "    next_dist = target_model(next_state)\n",
    "    next_action = next_dist.mean(2).max(1)[1]\n",
    "    next_action = next_action.unsqueeze(1).unsqueeze(1).expand(batch_size, 1, num_quant)\n",
    "    next_dist = next_dist.gather(1, next_action).squeeze(1).cpu().data\n",
    "\n",
    "    expected_quant = reward.unsqueeze(1) + 0.99 * next_dist * (1 - done.unsqueeze(1))\n",
    "    expected_quant = Variable(expected_quant)\n",
    "\n",
    "    quant_idx = torch.sort(dist, 1, descending=False)[1]\n",
    "\n",
    "    tau_hat = torch.linspace(0.0, 1.0 - 1./num_quant, num_quant) + 0.5 / num_quant\n",
    "    tau_hat = tau_hat.unsqueeze(0).repeat(batch_size, 1)\n",
    "    quant_idx = quant_idx.cpu().data\n",
    "    batch_idx = np.arange(batch_size)\n",
    "    tau = tau_hat[:, quant_idx][batch_idx, batch_idx]\n",
    "        \n",
    "    return tau, expected_quant"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 106,
   "metadata": {},
   "outputs": [],
   "source": [
    "num_quant = 51\n",
    "Vmin = -10\n",
    "Vmax = 10\n",
    "\n",
    "current_model = QRDQN(env.observation_space.shape[0], env.action_space.n, num_quant)\n",
    "target_model  = QRDQN(env.observation_space.shape[0], env.action_space.n, num_quant)\n",
    "\n",
    "if USE_CUDA:\n",
    "    current_model = current_model.cuda()\n",
    "    target_model  = target_model.cuda()\n",
    "    \n",
    "optimizer = optim.Adam(current_model.parameters())\n",
    "\n",
    "replay_buffer = ReplayBuffer(10000)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 107,
   "metadata": {},
   "outputs": [],
   "source": [
    "def update_target(current_model, target_model):\n",
    "    target_model.load_state_dict(current_model.state_dict())\n",
    "    \n",
    "update_target(current_model, target_model)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<h2>Computing Temporal Difference Loss</h2>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 119,
   "metadata": {},
   "outputs": [],
   "source": [
    "def compute_td_loss(batch_size):\n",
    "    state, action, reward, next_state, done = replay_buffer.sample(batch_size) \n",
    "\n",
    "    state      = Variable(torch.FloatTensor(np.float32(state)))\n",
    "    next_state = Variable(torch.FloatTensor(np.float32(next_state)), volatile=True)\n",
    "    action     = Variable(torch.LongTensor(action))\n",
    "    reward     = torch.FloatTensor(reward)\n",
    "    done       = torch.FloatTensor(np.float32(done))\n",
    "\n",
    "    dist = current_model(state)\n",
    "    action = action.unsqueeze(1).unsqueeze(1).expand(batch_size, 1, num_quant)\n",
    "    dist = dist.gather(1, action).squeeze(1)\n",
    "    \n",
    "    tau, expected_quant = projection_distribution(dist, next_state, reward, done)\n",
    "    k = 1\n",
    "    \n",
    "    huber_loss = 0.5 * u.abs().clamp(min=0.0, max=k).pow(2)\n",
    "    huber_loss += k * (u.abs() -  u.abs().clamp(min=0.0, max=k))\n",
    "    quantile_loss = (tau - (u < 0).float()).abs() * huber_loss\n",
    "    loss = quantile_loss.sum() / num_quant\n",
    "        \n",
    "    optimizer.zero_grad()\n",
    "    loss.backward()\n",
    "    nn.utils.clip_grad_norm(current_model.parameters(), 0.5)\n",
    "    optimizer.step()\n",
    "    \n",
    "    return loss"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 109,
   "metadata": {},
   "outputs": [],
   "source": [
    "def plot(frame_idx, rewards, losses):\n",
    "    clear_output(True)\n",
    "    plt.figure(figsize=(20,5))\n",
    "    plt.subplot(131)\n",
    "    plt.title('frame %s. reward: %s' % (frame_idx, np.mean(rewards[-10:])))\n",
    "    plt.plot(rewards)\n",
    "    plt.subplot(132)\n",
    "    plt.title('loss')\n",
    "    plt.plot(losses)\n",
    "    plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<h2>Training</h2>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 110,
   "metadata": {},
   "outputs": [],
   "source": [
    "epsilon_start = 1.0\n",
    "epsilon_final = 0.01\n",
    "epsilon_decay = 500\n",
    "\n",
    "epsilon_by_frame = lambda frame_idx: epsilon_final + (epsilon_start - epsilon_final) * math.exp(-1. * frame_idx / epsilon_decay)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 111,
   "metadata": {},
   "outputs": [],
   "source": [
    "num_frames = 10000\n",
    "batch_size = 32\n",
    "gamma      = 0.99\n",
    "\n",
    "losses = []\n",
    "all_rewards = []\n",
    "episode_reward = 0"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 112,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\nSUVORK5CYII=\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x7f42c32e2b10>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "state = env.reset()\n",
    "for frame_idx in range(1, num_frames + 1):\n",
    "    action = current_model.act(state, epsilon_by_frame(frame_idx))\n",
    "    \n",
    "    next_state, reward, done, _ = env.step(action)\n",
    "    replay_buffer.push(state, action, reward, next_state, done)\n",
    "    \n",
    "    state = next_state\n",
    "    episode_reward += reward\n",
    "    \n",
    "    if done:\n",
    "        state = env.reset()\n",
    "        all_rewards.append(episode_reward)\n",
    "        episode_reward = 0\n",
    "        \n",
    "    if len(replay_buffer) > batch_size:\n",
    "        loss = compute_td_loss(batch_size)\n",
    "        losses.append(loss.data[0])\n",
    "        \n",
    "    if frame_idx % 200 == 0:\n",
    "        plot(frame_idx, all_rewards, losses)\n",
    "        \n",
    "    if frame_idx % 1000 == 0:\n",
    "        update_target(current_model, target_model)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<p><hr></p>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<h1>Atari Environment</h1>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 120,
   "metadata": {},
   "outputs": [],
   "source": [
    "from common.wrappers import make_atari, wrap_deepmind, wrap_pytorch"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 121,
   "metadata": {},
   "outputs": [],
   "source": [
    "env_id = \"PongNoFrameskip-v4\"\n",
    "env    = make_atari(env_id)\n",
    "env    = wrap_deepmind(env)\n",
    "env    = wrap_pytorch(env)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 122,
   "metadata": {},
   "outputs": [],
   "source": [
    "class QRCnnDQN(nn.Module):\n",
    "    def __init__(self, input_shape, num_actions, num_quants):\n",
    "        super(QRCnnDQN, self).__init__()\n",
    "        \n",
    "        self.input_shape = input_shape\n",
    "        self.num_actions = num_actions\n",
    "        self.num_quants  = num_quants\n",
    "        \n",
    "        self.features = nn.Sequential(\n",
    "            nn.Conv2d(input_shape[0], 32, kernel_size=8, stride=4),\n",
    "            nn.ReLU(),\n",
    "            nn.Conv2d(32, 64, kernel_size=4, stride=2),\n",
    "            nn.ReLU(),\n",
    "            nn.Conv2d(64, 64, kernel_size=3, stride=1),\n",
    "            nn.ReLU()\n",
    "        )\n",
    "        \n",
    "        self.value = nn.Sequential(\n",
    "            nn.Linear(self.feature_size(), 512),\n",
    "            nn.ReLU(),\n",
    "            nn.Linear(512, self.num_actions * self.num_quants)\n",
    "        )\n",
    "        \n",
    "    def forward(self, x):\n",
    "        batch_size = x.size(0)\n",
    "        \n",
    "        x = self.features(x)\n",
    "        x = x.view(batch_size, -1)\n",
    "        \n",
    "        x = self.value(x)\n",
    "        x = x.view(batch_size, self.num_actions, self.num_quants)\n",
    "        \n",
    "        return x\n",
    "    \n",
    "    def q_values(self, x):\n",
    "        x = self.forward(x)\n",
    "        return x.mean(2)\n",
    "        \n",
    "    def feature_size(self):\n",
    "        return self.features(autograd.Variable(torch.zeros(1, *self.input_shape))).view(1, -1).size(1)\n",
    "        \n",
    "    def act(self, state, epsilon):\n",
    "        if random.random() > epsilon:\n",
    "            state = Variable(torch.FloatTensor(np.array(state, dtype=np.float32)).unsqueeze(0), volatile=True)\n",
    "            qvalues = self.forward(state).mean(2)\n",
    "            action  = qvalues.max(1)[1]\n",
    "            action  = action.data.cpu().numpy()[0]\n",
    "        else:\n",
    "            action = random.randrange(self.num_actions)\n",
    "        return action"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 123,
   "metadata": {},
   "outputs": [],
   "source": [
    "num_quant = 51\n",
    "Vmin = -10\n",
    "Vmax = 10\n",
    "\n",
    "current_model = QRCnnDQN(env.observation_space.shape, env.action_space.n, num_quant)\n",
    "target_model  = QRCnnDQN(env.observation_space.shape, env.action_space.n, num_quant)\n",
    "\n",
    "if USE_CUDA:\n",
    "    current_model = current_model.cuda()\n",
    "    target_model  = target_model.cuda()\n",
    "    \n",
    "update_target(current_model, target_model)\n",
    "    \n",
    "optimizer = optim.Adam(current_model.parameters(), lr=5e-5)\n",
    "\n",
    "replay_initial = 10000\n",
    "replay_buffer  = ReplayBuffer(100000)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 124,
   "metadata": {},
   "outputs": [],
   "source": [
    "epsilon_start = 1.0\n",
    "epsilon_final = 0.01\n",
    "epsilon_decay = 30000\n",
    "\n",
    "epsilon_by_frame = lambda frame_idx: epsilon_final + (epsilon_start - epsilon_final) * math.exp(-1. * frame_idx / epsilon_decay)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "num_frames = 1000000\n",
    "batch_size = 32\n",
    "gamma      = 0.99\n",
    "\n",
    "losses = []\n",
    "all_rewards = []\n",
    "episode_reward = 0\n",
    "\n",
    "state = env.reset()\n",
    "for frame_idx in range(1, num_frames + 1):\n",
    "    action = current_model.act(state, epsilon_by_frame(frame_idx))\n",
    "    \n",
    "    next_state, reward, done, _ = env.step(action)\n",
    "    replay_buffer.push(state, action, reward, next_state, done)\n",
    "    \n",
    "    state = next_state\n",
    "    episode_reward += reward\n",
    "    \n",
    "    if done:\n",
    "        state = env.reset()\n",
    "        all_rewards.append(episode_reward)\n",
    "        episode_reward = 0\n",
    "        \n",
    "    if len(replay_buffer) > replay_initial:\n",
    "        loss = compute_td_loss(batch_size)\n",
    "        losses.append(loss.data[0])\n",
    "        \n",
    "    if frame_idx % 10000 == 0:\n",
    "        plot(frame_idx, all_rewards, losses)\n",
    "        \n",
    "    if frame_idx % 1000 == 0:\n",
    "        update_target(current_model, target_model)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 2",
   "language": "python",
   "name": "python2"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 2
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython2",
   "version": "2.7.13"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
